#include "DimensionConvertor.h"



void DimensionConvertor::projectiveToReal(float* data, float3* out, int x, int y, int size){
	//float3* temp_device; cudaMalloc(&temp_device, x * y * sizeof(float3));
	



	setResolution(x, y);

	thrust::counting_iterator<int> index(0);
	float3 reset;
	reset.x = 0.0;
	reset.y = 0.0;
	reset.z = 0.0;

	thrust::fill(
		thrust::device_ptr<float3>(out),
		thrust::device_ptr<float3>(out) + size,
		reset
	);

	thrust::device_ptr<float> dev_ptr(data);
	convert_ptr cvt(x, y, F, p_size);

	thrust::transform(
		thrust::make_zip_iterator(thrust::make_tuple(dev_ptr, index)),
		thrust::make_zip_iterator(thrust::make_tuple(dev_ptr + size, index + size)),
		thrust::device_ptr<float3>(out), 
		cvt
	);

	/*cudaMemcpy(out, temp_device, sizeof(float3) * x * y, cudaMemcpyDeviceToHost);
	cudaFree(temp_device);*/

	/*float3* me = new float3[x * y];
	cudaMemcpy(me, out, x * y * sizeof(float3), cudaMemcpyDeviceToHost);
	for(int i = 0; i < x * y; i++)
		if(me[i].z > 0.0)
			std::cout << me[i].z << std::endl;

	delete[] me;*/
	/*std::cout << out << std::endl;
	std::cout << "projecxting"<<std::endl;*/
}


void DimensionConvertor::projectiveToReal(float3* data, float3* out, int x, int y, int size){
	setResolution(x, y);

	thrust::transform(
		thrust::device_ptr<float3>(data),
		thrust::device_ptr<float3>(data) + size,
		thrust::device_ptr<float3>(out),
		convert_ptr(x, y, F, p_size)
	);
}

void DimensionConvertor::projectiveToRealInterp(float* data, float3* out, int x, int y, int size){
	setResolution(x, y);
	thrust::counting_iterator<int> index(0);
	float3 reset;
	reset.x = 0.0;
	reset.y = 0.0;
	reset.z = 0.0;

	thrust::fill(
		thrust::device_ptr<float3>(out),
		thrust::device_ptr<float3>(out) + size,
		reset
	);

	thrust::device_ptr<float> dev_ptr(data);

	//thrust::transform(
	//	thrust::make_zip_iterator(thrust::make_tuple(dev_ptr, index)),
	//	thrust::make_zip_iterator(thrust::make_tuple(dev_ptr + size, index + size)),
	//	thrust::device_ptr<float3>(out), 
	//	cvt
	//);



	thrust::transform(
		thrust::make_zip_iterator(thrust::make_tuple(dev_ptr, index)),
		thrust::make_zip_iterator(thrust::make_tuple(dev_ptr + size, index + size)),
		thrust::device_ptr<float3>(out), 
		convert_ptr_int(x, y, F, p_size)
	);


}





__global__ void shiftCoordinates(float3* data, float* out, int width, int height){
	int x = blockIdx.x * blockDim.x + threadIdx.x;
	int y = blockIdx.y * blockDim.y + threadIdx.y;	

	float3* ref = &data[x + y * width];	
	int access = ref->x + ref->y * width;
	out[x + y * width] = 0.0;

	if(access >= 0 && access < width * height && ref->z > 100.0)
		out[access] = ref->z;
}


void DimensionConvertor::realToProjective(float3* data, float* out, int x, int y){
	realToProjectiveHelper(data, x, y);
	dim3 blockSize(32, 12);
	dim3 gridSize(x / 32, y / 12);

	shiftCoordinates<<<gridSize, blockSize>>>(data, out, x, y);
}


__global__ void shiftCoordinates(float3* data, float* weight, float2* out, int width, int height){
	int x = blockIdx.x * blockDim.x + threadIdx.x;
	int y = blockIdx.y * blockDim.y + threadIdx.y;
	
	out[x + y * width].x = 0.0;
	out[x + y * width].y = 0.0;

	float3* ref = &data[x + y * width];	
	int access = ref->x + ref->y * width;

	if(access >= 0 && access < width * height && ref->z > 100.0){
		out[access].x = ref->z;
		out[access].y = weight[x + y * width];
	}
}

void DimensionConvertor::realToProjective(float3* data, float* weight, float2* out, int x, int y){
	realToProjectiveHelper(data, x, y);

	dim3 blockSize(32, 12);
	dim3 gridSize(x / 32, y / 12);

	shiftCoordinates<<<gridSize, blockSize>>>(data, weight, out, x, y);
}


void DimensionConvertor::realToProjectiveHelper(float3* data, int x, int y){
	setResolution(x, y);

	thrust::transform(
		thrust::device_ptr<float3>(data),
		thrust::device_ptr<float3>(data) + x * y,
		thrust::device_ptr<float3>(data),
		convert_rtp(x, y, F, p_size)
	);
}
